package com.wuyu.ibatis.builder;

import com.wuyu.ibatis.config.Configuration;
import com.wuyu.ibatis.constants.ConfigConstants;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.Assert;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;


/**
 * xml配置构建
 */
public class XMLConfigBuilder {

    private final Configuration configuration;
    private final Document config;

    public XMLConfigBuilder(Document config) {
        this.configuration = new Configuration();
        this.config = config;
    }

    public Configuration parse() {
        Element element = config.getDocumentElement();
        parseConfiguration(element);
        return configuration;
    }

    /**
     * 解析配置信息
     *
     * @param root
     */
    private void parseConfiguration(Element root) {
        try {
            NodeList nodeList = root.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (node instanceof Element) {
                    Element element = (Element) node;
                    String nodeName = element.getNodeName();
                    Assert.notNull(element, "Element must not be null");
                    Assert.notNull(element.getNodeName(), "Element name must not be null");
                    switch (nodeName) {
                        case ConfigConstants.PROPERTIES:
                            parsePropertiesElement(element);
                            break;
                        case ConfigConstants.MAPPERS:
                            parseMappersElement(element);
                            break;
                    }
                }
            }
        } catch (Exception e) {
            throw new BuilderException("Error parsing Configuration. Cause: " + e, e);
        }
    }

    /**
     * mapper文件解析
     *
     * @param mappers
     */
    private void parseMappersElement(Element mappers) throws IOException {
        NodeList nodeList = mappers.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node instanceof Element) {
                Element mapper = (Element) node;
                String nodeName = mapper.getNodeName();
                Assert.notNull(mapper, "Element must not be null");
                Assert.notNull(nodeName, "Element name must not be null");
                if (ConfigConstants.MAPPER.equals(nodeName)) {
                    String resource = mapper.getAttribute("resource");
                    XMLMapperBuilder mapperParser = new XMLMapperBuilder(configuration, resource);
                    mapperParser.parse();
                }
            }
        }
    }


    /**
     * 数据库连接属性解析
     *
     * @param element
     * @throws IOException
     */
    private void parsePropertiesElement(Element element) throws IOException {
        String resource = element.getAttribute("resource");
        InputStream in = null;
        try {
            Properties properties = new Properties();
            in = new ClassPathResource(resource).getInputStream();
            properties.load(in);
            configuration.setVariables(properties);
        } catch (Exception e) {
            throw new BuilderException("Error parsing Configuration properties. Cause: " + e, e);
        } finally {
            if (in != null) {
                in.close();
            }
        }
    }


}
